package com.offdissys.common.utils.token;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.offdissys.common.core.constant.TokenResultEnum;
import com.offdissys.common.core.exception.CommException;
import com.offdissys.common.utils.bean.BeanUtils;
import com.offdissys.common.utils.domain.BaseTokenObj;
import com.offdissys.common.utils.domain.TokenConstants;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ZhangHaiWen
 * @title: Token
 * @projectName parent
 * @description: Token基础类 其他token实现都要继承该类,实现默认构造函数 和 带参构造函数
 * @date 2022/3/710:44
 */
public class DefaultToken extends AbstractToken {

    private TokenConfig tokenConfig;

    public DefaultToken() {
         super();
    }

    public DefaultToken(TokenConfig tokenConfig) {
        super(tokenConfig);
        this.tokenConfig = tokenConfig;
    }

    @Override
    public String buildToken(BaseTokenObj obj) {
        if(ObjectUtil.isEmpty(obj)){
            throw new CommException(TokenResultEnum.OBJECT_NOT_EMPTY);
        }
        try {
            Algorithm algorithm = Algorithm.HMAC256(tokenConfig.secretCode());
            Map<String, Object> map = new HashMap<String, Object>();
            Date nowDate = new Date();
            // 设置过期时间
            Date expireDate = DateUtil.offsetDay(nowDate,tokenConfig.offsetDay());
            map.put("alg", "HS256");
            map.put("typ", "JWT");
            String token = JWT.create()
                    /*设置头部信息 Header*/
                    .withHeader(map)
                    /* 设置加密内容 */
                    .withClaim(TokenConstants.CLAIM_NAME, BeanUtils.bean2Map(obj))
                    //签名是有谁生成 例如 服务器
                    .withIssuer(TokenConstants.SERVICE)
                    //生成签名的时间
                    .withIssuedAt(nowDate)
                    //签名过期的时间
                    .withExpiresAt(expireDate)
                    //设置签名使用的签名算法和签名使用的秘钥
                    .sign(algorithm);
            return token;
        } catch (JWTCreationException exception){
            throw new CommException(TokenResultEnum.TOKEN_BUILD_ERROR);
        }
    }

    @Override
    public <T extends BaseTokenObj> T analysisToken(String tokenStr, Class<T> tClass) {
        if(StrUtil.isBlank(tokenStr)){
            throw new CommException(TokenResultEnum.TOKEN_NOT_EMPTY);
        }
        try {
            Algorithm algorithm = Algorithm.HMAC256(tokenConfig.secretCode());
            JWTVerifier verifier = JWT.require(algorithm).withIssuer(TokenConstants.SERVICE).build();
            DecodedJWT jwt = verifier.verify(tokenStr);
            Map<String, Claim> claims = jwt.getClaims();
            Map<String, Object> map = claims.get(TokenConstants.CLAIM_NAME).asMap();
            return (T)BeanUtils.map2Bean(map,tClass);
        } catch (JWTVerificationException exception){
            throw new CommException(TokenResultEnum.USER_OVER_TIME_LOGIN);
        }
    }

}
